package com.imooc.course.system.controller.admin;

import com.alibaba.fastjson.JSON;
import com.imooc.course.server.constants.Constant;
import com.imooc.course.server.dto.LoginUserDto;
import com.imooc.course.server.dto.PageDto;
import com.imooc.course.server.dto.ResponseDto;
import com.imooc.course.server.dto.UserDto;
import com.imooc.course.server.service.UserService;
import com.imooc.course.server.utils.CopyUtil;
import com.imooc.course.server.utils.UuidUtil;
import com.imooc.course.server.utils.ValidatorUtil;
import com.imooc.course.system.form.PageForm;
import com.imooc.course.system.form.UserForm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/admin/user")
public class UserController {

    private static final Logger log = LoggerFactory.getLogger(UserController.class);
    public static final String BUSINESS_NAME = "用户";

    @Resource(name = "userService")
    private UserService userService;

    @Resource
    public RedisTemplate redisTemplate;


    /**
     * 查询列表
     * @param pageForm 传入的page和size
     * @return
     */
    @PostMapping("/list")
    public ResponseDto getList(@RequestBody PageForm pageForm) {
        PageDto pageDto = CopyUtil.copy(pageForm, PageDto.class);
        userService.getList(pageDto);
        return ResponseDto.success().setContent(pageDto);
    }

    /**
     * 保存，id有值为更新，id无值为新增
     * @param userForm
     * @return
     */
    @PostMapping("/save")
    public ResponseDto addUser(@RequestBody UserForm userForm) {
        //入参检查
        ValidatorUtil.notNull(userForm.getLoginName(), "登陆名");
        ValidatorUtil.minimumToMaximum(userForm.getLoginName(), "登陆名", 1, 50);
        ValidatorUtil.minimumToMaximum(userForm.getName(), "昵称", 1, 50);
        ValidatorUtil.notNull(userForm.getPassword(), "密码");

        UserDto userDto = CopyUtil.copy(userForm, UserDto.class);
        log.info("第一次 password 加密 = {}",userForm.getPassword());
        //前端上传前加密一次，后端收到后再加密一次。
        /**
         * MD5实际上是不能解的，
         * 凡是宣称能解MD5的，其实都是提前将常见的密码组合计算为16进制MD5字符值后，
         * 将计算出来的MD5值为KEY，密码为value，存进数据库。
         * 当你要使用他的解密服务时，就是在它的数据库中查询。
         * 其本质是肓猜。
         * 只要在用户的密码前面或后面或前后都加上一串保密不暴露的盐值(开发者定义的随机字符串)再生成MD5值，
         * 就难以被破解，即使破解后得到的也是密码和随机字符串的组合值，并没有得到用户的真实密码。
         * 最后，用户创建时，密码传到后端也会再被加密一次，
         * 这样，无论是后端密码泄露还是前端密码泄露，别人也无法得到真正的用户密码。
         * @type {string}
         */
        userDto.setPassword(DigestUtils.md5DigestAsHex(userDto.getPassword().getBytes()));
        userService.save(userDto);
        log.info("第二次 password 加密 = {}",userDto.getPassword());
        return ResponseDto.success();
    }

    /**
     * 重置密码
     * @param userForm
     * @return
     */
    @PostMapping("/save/password")
    public ResponseDto editPassword(@RequestBody UserForm userForm) {
        //入参检查
        ValidatorUtil.notNull(userForm.getPassword(), "密码");

        UserDto userDto = CopyUtil.copy(userForm, UserDto.class);
        log.info("修改后的 password 第一次加密 = {}",userForm.getPassword());
        //前端上传前加密一次，后端收到后再加密一次。
        /**
         * MD5实际上是不能解的，
         * 凡是宣称能解MD5的，其实都是提前将常见的密码组合计算为16进制MD5字符值后，
         * 将计算出来的MD5值为KEY，密码为value，存进数据库。
         * 当你要使用他的解密服务时，就是在它的数据库中查询。
         * 其本质是肓猜。
         * 只要在用户的密码前面或后面或前后都加上一串保密不暴露的盐值(开发者定义的随机字符串)再生成MD5值，
         * 就难以被破解，即使破解后得到的也是密码和随机字符串的组合值，并没有得到用户的真实密码。
         * 最后，用户创建时，密码传到后端也会再被加密一次，
         * 这样，无论是后端密码泄露还是前端密码泄露，别人也无法得到真正的用户密码。
         * @type {string}
         */
        userDto.setPassword(DigestUtils.md5DigestAsHex(userDto.getPassword().getBytes()));
        userService.savePassword(userDto);
        log.info("修改后的 password 第二次加密 = {}",userDto.getPassword());
        return ResponseDto.success();
    }

    /**
     * 删除
     * @param id
     * @return
     */
    @DeleteMapping("/delete/{id}")
    public ResponseDto del(@PathVariable String id) {
        userService.delete(id);
        return ResponseDto.success();
    }

    /**
     * 用户登录
     * @param userForm
     * @param request
     * @return
     */
    @PostMapping("/login")
    public ResponseDto login(@RequestBody UserForm userForm, HttpServletRequest request) {

        String kaptcha = (String)redisTemplate.opsForValue().get(userForm.getImageCodeToken());
        if (StringUtils.isEmpty(kaptcha)) {
            log.info("用户登录失败，验证码已过期 kaptcha = {}", kaptcha);
            redisTemplate.delete(userForm.getImageCodeToken());
            return ResponseDto.fail().setMsg("验证码已过期");
        }
        if (!userForm.getImageCode().trim().toLowerCase().equals(kaptcha.toLowerCase())) {
            log.info("用户登录失败，验证码错误 用户输入 = {}，kaptcha = {}", userForm.getImageCode().trim().toLowerCase(), kaptcha);
            redisTemplate.delete(userForm.getImageCodeToken());
            return ResponseDto.fail().setMsg("验证码错误");
        }

        redisTemplate.delete(userForm.getImageCodeToken());

        UserDto userDto = CopyUtil.copy(userForm, UserDto.class);
        log.info("发送登录请求前的 password 第一次加密 = {}",userForm.getPassword());
        //前端登录时会将密码加密一次，后端收到后再加密一次。
        /**
         * MD5实际上是不能解的，
         * 凡是宣称能解MD5的，其实都是提前将常见的密码组合计算为16进制MD5字符值后，
         * 将计算出来的MD5值为KEY，密码为value，存进数据库。
         * 当你要使用他的解密服务时，就是在它的数据库中查询。
         * 其本质是肓猜。
         * 只要在用户的密码前面或后面或前后都加上一串保密不暴露的盐值(开发者定义的随机字符串)再生成MD5值，
         * 就难以被破解，即使破解后得到的也是密码和随机字符串的组合值，并没有得到用户的真实密码。
         * 最后，用户创建时，密码传到后端也会再被加密一次，
         * 这样，无论是后端密码泄露还是前端密码泄露，别人也无法得到真正的用户密码。
         * @type {string}
         */
        userDto.setPassword(DigestUtils.md5DigestAsHex(userDto.getPassword().getBytes()));
        log.info("后端收到 password 第二次加密 = {}",userDto.getPassword());

        LoginUserDto loginUser = userService.login(userDto);
        loginUser.setToken(UuidUtil.getShortUuid());

        redisTemplate.opsForValue().set(loginUser.getToken(), JSON.toJSONString(loginUser), 3600, TimeUnit.SECONDS);

        return ResponseDto.success().setContent(loginUser);
    }

    /**
     * 退出登录
     * @param token
     * @return
     */
    @GetMapping("/logout/{token}")
    public ResponseDto logout(@PathVariable String token) {

        redisTemplate.delete(token);

        return ResponseDto.success();
    }

    /**
     * 获取所有用户
     * @return
     */
    @PostMapping("/all")
    public ResponseDto getAllUser() {

        List<UserDto> list = userService.getListAll();

        return ResponseDto.success().setContent(list);
    }
}
